/**
 * ***************************************************************
 * JADE - Java Agent DEvelopment Framework is a framework to develop
 * multi-agent systems in compliance with the FIPA specifications.
 * Copyright (C) 2000 CSELT S.p.A.
 *
 * GNU Lesser General Public License
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation,
 * version 2.1 of the License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA  02111-1307, USA.
 * **************************************************************
 */
package jade;

//#MIDP_EXCLUDE_FILE

import jade.core.Runtime;
import jade.core.Profile;
import jade.core.ProfileImpl;
import jade.core.ProfileException;

import jade.util.leap.Properties;
import jade.util.ExtendedProperties;
import jade.util.Logger;

/**
 * Boots the <B><em>JADE</em></b> system, parsing command line arguments.
 *
 * @author Giovanni Rimassa - Universita' di Parma
 * @author Giovanni Caire - TILAB
 * @author Nicolas Lhuillier - Motorola
 * @author Jerome Picault - Motorola
 * @version $Date: 2010-04-19 16:16:41 +0200 (lun, 19 apr 2010) $ $Revision: 6320 $
 */
public class Boot
{
    public static final String DEFAULT_FILENAME = "leap.properties";
    private static Logger logger = Logger.getMyLogger( "jade.Boot" );

    /**
     * Fires up the <b><em>JADE</em></b> system.
     * This method initializes the Profile Manager and then starts the
     * bootstrap process for the <B><em>JADE</em></b>
     * agent platform.
     */
    public static void main( String args[] )
    {
        try
        {
            // Create the Profile
            ProfileImpl p = null;
            if( args.length > 0 )
            {
                if( args[0].startsWith( "-" ) )
                {
                    // Settings specified as command line arguments
                    Properties pp = parseCmdLineArgs( args );
                    if( pp != null )
                    {
                        p = new ProfileImpl( pp );
                    }
                    else
                    {
                        // One of the "exit-immediately" options was specified!
                        return;
                    }
                }
                else
                {
                    // Settings specified in a property file
                    p = new ProfileImpl( args[0] );
                }
            }
            else
            {
                // Settings specified in the default property file
                p = new ProfileImpl( DEFAULT_FILENAME );
            }

            // Start a new JADE runtime system
            Runtime.instance().setCloseVM( true );
            //#PJAVA_EXCLUDE_BEGIN
            // Check whether this is the Main Container or a peripheral container
            if( p.getBooleanProperty( Profile.MAIN, true ) )
            {
                Runtime.instance().createMainContainer( p );
            }
            else
            {
                Runtime.instance().createAgentContainer( p );
            }
            //#PJAVA_EXCLUDE_END
            /*#PJAVA_INCLUDE_BEGIN
               // Starts the container in SINGLE_MODE (Only one per JVM)
               Runtime.instance().startUp(p);
               #PJAVA_INCLUDE_END*/
        }
        catch( ProfileException pe )
        {
            System.err.println( "Error creating the Profile [" + pe.getMessage() + "]" );
            pe.printStackTrace();
            printUsage();
            //System.err.println("Usage: java jade.Boot <filename>");
            System.exit( -1 );
        }
        catch( IllegalArgumentException iae )
        {
            System.err.println( "Command line arguments format error. " + iae.getMessage() );
            iae.printStackTrace();
            printUsage();
            //System.err.println("Usage: java jade.Boot <filename>");
            System.exit( -1 );
        }
    }

    /**
     * Default constructor.
     */
    public Boot()
    {
    }


    public static Properties parseCmdLineArgs( String[] args ) throws IllegalArgumentException
    {
        Properties props = new ExtendedProperties();

        int i = 0;
        while( i < args.length )
        {
            if( args[i].startsWith( "-" ) )
            {
                // Parse next option

                // Switch options require special handling
                if( args[i].equalsIgnoreCase( "-version" ) )
                {
                    logger.log( Logger.INFO, "----------------------------------\n" + Runtime.getCopyrightNotice() + "----------------------------------------" );
                    return null;
                }
                if( args[i].equalsIgnoreCase( "-help" ) )
                {
                    printUsage();
                    return null;
                }
                if( args[i].equalsIgnoreCase( "-container" ) )
                {
                    props.setProperty( Profile.MAIN, "false" );
                }
                else if( args[i].equalsIgnoreCase( "-" + Profile.LOCAL_SERVICE_MANAGER ) )
                {
                    props.setProperty( Profile.LOCAL_SERVICE_MANAGER, "true" );
                }
                else if( args[i].equalsIgnoreCase( "-" + Profile.GUI ) )
                {
                    props.setProperty( Profile.GUI, "true" );
                }
                else if( args[i].equalsIgnoreCase( "-" + Profile.NO_MTP ) )
                {
                    props.setProperty( Profile.NO_MTP, "true" );
                }
                // Options that can be specified in different ways require special handling
                else if( args[i].equalsIgnoreCase( "-name" ) )
                {
                    if( ++i < args.length )
                    {
                        props.setProperty( Profile.PLATFORM_ID, args[i] );
                    }
                    else
                    {
                        throw new IllegalArgumentException( "No platform name specified after \"-name\" option" );
                    }
                }
                else if( args[i].equalsIgnoreCase( "-mtp" ) )
                {
                    if( ++i < args.length )
                    {
                        props.setProperty( Profile.MTPS, args[i] );
                    }
                    else
                    {
                        throw new IllegalArgumentException( "No mtps specified after \"-mtp\" option" );
                    }
                }
                // The -conf option requires special handling
                else if( args[i].equalsIgnoreCase( "-conf" ) )
                {
                    if( ++i < args.length )
                    {
                        // Some parameters are specified in a properties file
                        try
                        {
                            props.load( args[i] );
                        }
                        catch( Exception e )
                        {
                            if( logger.isLoggable( Logger.SEVERE ) )
                            {
                                logger.log( Logger.SEVERE, "WARNING: error loading properties from file " + args[i] + ". " + e );
                            }
                        }
                    }
                    else
                    {
                        throw new IllegalArgumentException( "No configuration file name specified after \"-conf\" option" );
                    }
                }
                // Default handling for all other properties
                else
                {
                    String name = args[i].substring( 1 );
                    if( ++i < args.length )
                    {
                        props.setProperty( name, args[i] );
                    }
                    else
                    {
                        throw new IllegalArgumentException( "No value specified for property \"" + name + "\"" );
                    }
                }
                ++i;
            }
            else
            {
                // Get agents at the end of command line
                if( props.getProperty( Profile.AGENTS ) != null )
                {
                    if( logger.isLoggable( Logger.WARNING ) )
                    {
                        logger.log( Logger.WARNING, "WARNING: overriding agents specification set with the \"-agents\" option" );
                    }
                }
                String agents = args[i];
                props.setProperty( Profile.AGENTS, args[i] );
                if( ++i < args.length )
                {
                    if( logger.isLoggable( Logger.WARNING ) )
                    {
                        logger.log( Logger.WARNING, "WARNING: ignoring command line argument " + args[i] + " occurring after agents specification" );
                    }
                    if( agents != null && agents.indexOf( '(' ) != -1 && !agents.endsWith( ")" ) )
                    {
                        if( logger.isLoggable( Logger.WARNING ) )
                        {
                            logger.log( Logger.WARNING, "Note that agent arguments specifications must not contain spaces" );
                        }
                    }
                    if( args[i].indexOf( ':' ) != -1 )
                    {
                        if( logger.isLoggable( Logger.WARNING ) )
                        {
                            logger.log( Logger.WARNING, "Note that agent specifications must be separated by a semicolon character \";\" without spaces" );
                        }
                    }
                }
                break;
            }
        }

        // Consistency check
        if( "true".equals( props.getProperty( Profile.NO_MTP ) ) && props.getProperty( Profile.MTPS ) != null )
        {
            if( logger.isLoggable( Logger.WARNING ) )
            {
                logger.log( Logger.WARNING, "WARNING: both \"-mtps\" and \"-nomtp\" options specified. The latter will be ignored" );
            }
            props.remove( Profile.NO_MTP );
        }

        return props;
    }

    public static void printUsage()
    {
        System.out.println( "Usage:" );
        System.out.println( "java -cp <classpath> jade.Boot [options] [agents]" );
        System.out.println( "Main options:" );
        System.out.println( "    -container" );
        System.out.println( "    -gui" );
        System.out.println( "    -name <platform name>" );
        System.out.println( "    -host <main container host>" );
        System.out.println( "    -port <main container port>" );
        System.out.println( "    -local-host <host where to bind the local server socket on>" );
        System.out.println( "    -local-port <port where to bind the local server socket on>" );
        System.out.println( "    -conf <property file to load configuration properties from>" );
        System.out.println( "    -services <semicolon separated list of service classes>" );
        System.out.println( "    -mtps <semicolon separated list of mtp-specifiers>" );
        System.out.println( "     where mtp-specifier = [in-address:]<mtp-class>[(comma-separated args)]" );
        System.out.println( "    -<property-name> <property-value>" );
        System.out.println( "Agents: [-agents] <semicolon separated list of agent-specifiers>" );
        System.out.println( "     where agent-specifier = <agent-name>:<agent-class>[(comma separated args)]" );
        System.out.println();
        System.out.println( "Look at the JADE Administrator's Guide for more details" );
    }
}

